package cn.tj.wenda.cloud.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.*;

/**
 * 查询参数处理通用类
 * 用于前端的传递参数在后端的处理以及后端拼凑查询条件时使用
 * 只支持一层的解析，嵌套不支持
 *
 * @author Wenda
 */
@Slf4j
public class QueryParam {
    private Map<String, Object> objParam = null;

    /**
     * 会对给定的JSON字符串进行URLDecoder.decode解码
     * @param params
     * @return
     */
    public static QueryParam parseObject(String params) {
        return new QueryParam(params);
    }

    private QueryParam() {
    }

    private QueryParam(String params) {
        try {
            String decJson = URLDecoder.decode(params, "utf-8");
            this.objParam = this.getMapFromJson(decJson);
        }
        catch (Exception ex) {
            log.error("将查询参数{}转换成查询对象时出错：{}", params, ex);
            this.objParam = new HashMap<>();
        }
    }

    private QueryParam(Map<String,Object> map){
        this.objParam = map;
    }

    /**
     * 判断给定的Key在查询对象中是否存在，存在返回true，不存在或者为空或者为null 返回false;
     *
     * @param key
     * @return
     */
    public Boolean isExist(String key) {
        if (!this.objParam.containsKey(key)) {
            return false;
        }
        if (this.objParam.get(key) == null) {
            return false;
        }

        if(this.objParam.get(key) instanceof List){
            return ((List<?>) this.objParam.get(key)).size() > 0;
        }
        else {
            String ret = this.getString(key);
            if (StringUtils.isEmpty(ret)) {
                return false;
            }
            return !(StringUtils.isEmpty(ret));
        }
    }

    /**
     * 返回给定查询参数的字符串类型的值，如果不存在或为空或为null都返回空
     * 会自动去除两边的空格
     * 中间的空格也会替换为空，为了防止SQL注入
     * 如果包含半角单引号，会清除
     *
     * @param key
     * @return
     */
    public String getString(String key) {
        if (!this.objParam.containsKey(key)) {
            return "";
        }
        String value = this.objParam.get(key).toString();
        value = StringUtils.trim(value);
        value = StringUtils.replace(value, " ", "");
        value = StringUtils.replace(value, "'", "");
        if (StringUtils.isEmpty(value)) {
            return "";
        }
        return value;
    }

    /**
     * 返回给定查询参数的整数类型的值，如果不存在，或包含非数字，或非整形，则返回null
     *
     * @param key
     * @return
     */
    public Integer getInteger(String key) {
        if (!this.objParam.containsKey(key)) {
            return null;
        }
        Object val = this.objParam.get(key);
        if (!ValidatorUtil.checkDigit(val.toString())) {
            return null;
        }
        return Integer.parseInt(val.toString());
    }

    /**
     * 返回给定查询参数的BigDecimal类型的值，如果不存在，或包含非数字，则返回null
     *
     * @param key
     * @return
     */
    public BigDecimal getBigDecimal(String key) {
        if (!this.objParam.containsKey(key)) {
            return null;
        }
        String val = this.objParam.get(key).toString();
        if (!ValidatorUtil.checkDecimals(val)) {
            return null;
        }
        return new BigDecimal(val);
    }

    /**
     * 给定的key的value为jsonObject时解析为QueryParam，其他返回null
     *
     * @param key
     * @return
     */
    public QueryParam getQueryParam(String key) {
        if (!this.objParam.containsKey(key)) {
            return null;
        }
        try{
            ObjectMapper mapper = this.getObjectMapper();
            if(this.objParam.get(key) instanceof Map){
                String strJSON = mapper.writeValueAsString(this.objParam.get(key));
                return QueryParam.parseObject(strJSON);
            }
            else{
                return null;
            }
        }
        catch (Exception ex) {
            log.error("将查询对象转换成JSON字符串时出错：", ex);
            return null;
        }

    }

    /**
     * 返回给定key的List类型的值，不存在返回空集合
     *
     * @param key
     * @return
     */
    public List<String> getListString(String key) {
        if (!this.objParam.containsKey(key)) {
            return new ArrayList<>();
        }
        if(this.objParam.get(key) instanceof List){
            return (List<String>)this.objParam.get(key);
        }
        else {
            return new ArrayList<>();
        }
    }

    /**
     * 用于Value值为JSONArray时解析
     *
     * @param key
     * @return
     */
    public List<QueryParam> getListQueryParam(String key) {
        List<QueryParam> lstRet = new ArrayList<>();
        if (!this.objParam.containsKey(key)) {
            return lstRet;
        }
        if(this.objParam.get(key) instanceof List){
            for(Object itm : (List)this.objParam.get(key)){
                if(itm instanceof Map){
                    lstRet.add(new QueryParam((Map)itm));
                }
            }
        }
        return lstRet;
    }

    /**
     * 根据传入参数生成新的查询对象
     *
     * @param key
     * @param value
     * @return
     */
    public static QueryParam generateParam(String key, String value) {
        Map<String,Object> map = new HashMap<>(16);
        map.put(key, value);
        return new QueryParam(map);
    }

    /**
     * 根据传入参数生成新的查询对象
     *
     * @param key
     * @param values
     * @return
     */
    public static QueryParam generateParam(String key, List<String> values) {
        Map<String,Object> map = new HashMap<>(16);
        map.put(key, values);
        return new QueryParam(map);
    }

    /**
     * 添加新的查询参数，调用之前必须先调用generateParam
     *
     * @param key
     * @param value
     * @return
     */
    public QueryParam addNewParam(String key, String value) {
        this.objParam.put(key, value);
        return this;
    }

    /**
     * 添加新的查询参数，调用之前必须先调用generateParam
     *
     * @param key
     * @param values
     * @return
     */
    public QueryParam addNewParam(String key, List<String> values) {
        this.objParam.put(key, values);
        return this;
    }

    /**
     * 将生成的QueryParam对象转成JSON字符串
     *
     * @return
     */
    public String toQueryParamString() {
        try {
            String jsonStr = this.getObjectMapper().writeValueAsString(this.objParam);
            return jsonStr;
        }
        catch (Exception ex) {
            log.error("将查询对象转换成JSON字符串时出错：", ex);
            return "";
        }
    }

    private ObjectMapper getObjectMapper() {
        return new ObjectMapper();
    }

    private Map<String, Object> getMapFromJson(String json) {

        if (StringUtils.isEmpty(json)) {
            return new HashMap<>(16);
        }
        Map<String, Object> ret;
        try {
            ObjectMapper mapper = this.getObjectMapper();
            ret = mapper.readValue(json, Map.class);
        }
        catch (Exception ex) {
            log.error("将查询参数转换成查询对象时出错：", ex);
            ret = new HashMap<>(16);
        }
        return ret;
    }

    private List<String> getListFromJson(String json) {
        ObjectMapper mapper = this.getObjectMapper();
        if (StringUtils.isEmpty(json)) {
            return new ArrayList<>();
        }
        List<String> ret;
        try {
            ret = mapper.readValue(json, new TypeReference<List<String>>() {});
        }
        catch (Exception ex) {
            log.error("将查询参数转换成查询对象时出错：", ex);
            ret = new ArrayList<>();
        }
        return ret;
    }
}
